using System;
using System.Text.RegularExpressions;
using Fadd.Globalization;
#if TEST
using Xunit;
#endif

namespace Fadd.Validation
{
    /// <summary>
    /// Validates a string as  http(s)/ftp url.
    /// </summary>
    public class ValidateWebURL : ValidateAttribute
    {
        private const string URLRegEx = @"^(http|https|ftp)\://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?";
        private const string DefaultMessage = "'{0}' is not a valid URL.";
        /// <summary>
        /// Name of the language item for this validation.
        /// </summary>
        public const string Name = "WebURL";

        /// <summary>
        /// Localize error if validation failed.
        /// </summary>
        /// <param name="fieldName">Localized field name.</param>
        /// <param name="validationLanguage">Language node with all validation translations.</param>
        /// <returns>A localized error message if the validation failed; otherwise null.</returns>
        /// <example>
        /// <code>
        /// attribute.Localize("FirstName", "'{0}' is required"); 
        /// // will return "'{0}' is required" if the validation failed, else null.
        /// </code>
        /// </example>
        public override string Format(string fieldName, ILanguageNode validationLanguage)
        {
            string format = validationLanguage == null ? DefaultMessage : validationLanguage[Name];
            return string.Format(format, fieldName);
        }

        /// <summary>
        /// Determines if the validation support the specified type.
        /// </summary>
        /// <param name="type">Property/Value type.</param>
        /// <returns>true if type is supported.</returns>
        /// <remarks>
        /// Used when validation objects are generated.
        /// </remarks>
        public override bool SupportsType(Type type)
        {
            return type == typeof(string);
            
        }

        /// <summary>
        /// Validate the URL
        /// </summary>
        /// <param name="instance">Object instance (of the object being tested).</param>
        /// <param name="value">Value to test</param>
        /// <returns>true if value is an URL; otherwise false.</returns>
        /// <exception cref="NotSupportedException">If type is not supported.</exception>
        public override bool Validate(object instance, object value)
        {
            if (value is string)
            {
                string url = (string)value;
                return Regex.IsMatch(url, URLRegEx);
            }

            throw new NotSupportedException(value.GetType() + " is not supported.");
        }


#if TEST
        [Fact]
        private static void Test()
        {
            ValidateWebURL attribute = new ValidateWebURL();
            Assert.True(attribute.Validate(null, "http://yahoo.com"));
            Assert.True(attribute.Validate(null, "http://yahoo.com:8080"));
            Assert.True(attribute.Validate(null, "http://www.yahoo.com"));
            Assert.True(attribute.Validate(null, "https://abc.yahoo.com"));
            Assert.True(attribute.Validate(null, "https://yahoo.com"));
            Assert.True(attribute.Validate(null, "https://yahoo.com/default.aspx?id=1"));
            Assert.True(attribute.Validate(null, "http://www.fwoxy.com/proxy.php?q=aHR0cDovL3d3dy50YW1pbG5ldC5jb20%3D&p=1e3"));
            Assert.True(attribute.Validate(null, "http://www.codeplex.com/fadd/Thread/View.aspx?ThreadId=35658"));
            Assert.True(attribute.Validate(null, "http://us.mg2.mail.yahoo.com/dc/launch?.rand=6rmf63bu50jst"));
            Assert.False(attribute.Validate(null, "http://yahoo"));
            Assert.False(attribute.Validate(null, "http(s)://yahoo.com"));
            Assert.False(attribute.Validate(null, "https://yahoo"));
            Assert.False(attribute.Validate(null, "yahoo.com"));
            
            
            attribute = new ValidateWebURL();
            Assert.True(attribute.Validate(null, "http://yahoo.com"));
            Assert.True(attribute.Validate(null, "https://yahoo.com"));
            Assert.False(attribute.Validate(null, "http://yahoo"));
            Assert.False(attribute.Validate(null, "http(s)://yahoo"));


            Assert.True(attribute.Validate(null, "ftp://moon.com/ftp_user/guest/tempdir"));
            Assert.True(attribute.Validate(null, "ftp://moon.com/ftp_user/guest/temp dir"));
            Assert.True(attribute.Validate(null, "ftp://1.2.3.4/ftp_user/guest/temp dir"));
            Assert.False(attribute.Validate(null, "ftp://moo n.com/ftp_user/guest/temp dir"));
            Assert.False(attribute.Validate(null, "ftp:\\moon.com/ftp_user/guest/temp dir"));
            

        }
#endif
    }
}
